package com.taobao.common.dao.persistence;

/**
 * Created on 2005-1-13
 */
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;

/**
 * 20006-08-21 duolong �������㷨���һ��������bug���޸������㷨���Ż�����֧�ֶ��С�
 * 
 * @author duolong �����ࡣ
 */
public class SqlMapComparator {
  private static final Object[] NO_ARGUMENTS = new Object[0];
  private List                  orderByList  = null;

  public SqlMapComparator(String orderByString) {
    if (orderByString != null) {
      orderByList = new ArrayList();

      StringTokenizer t = new StringTokenizer(orderByString, ",");

      while (t.hasMoreTokens()) {
        String s = t.nextToken();

        if ((s != null) && (s.length() > 1)) {
          if (s.charAt(0) == '_') {
            orderByList.add(s.substring(1));
            orderByList.add(new Integer(-1));
          } else {
            orderByList.add(s);
            orderByList.add(new Integer(1));
          }
        }
      }
    }
  }

  /**
   * ��Object����methodName����ȡ��һ��ֵ
   *
   * @param Object
   *          object ����
   * @param String
   *          methodName ������
   *
   * @return String ֵ
   */
  private Object getProperty(Object object, String methodName) throws Exception {
    Class claz = object.getClass();
    Method method = claz.getMethod(methodName, new Class[0]);

    return method.invoke(object, NO_ARGUMENTS);
  }

  /**
   * 
   * @param o1
   * @param o2
   *
   * @return
   */
  public int compare(Object o1, Object o2) throws Exception {
    if ((orderByList == null) || (o1 == null) || (o2 == null)) {
      return 0;
    }

    int result = 0;

    for (int i = 0; i < orderByList.size(); i += 2) {
      String methodName = (String) orderByList.get(i);
      Object v1 = getProperty(o1, methodName);
      Object v2 = getProperty(o2, methodName);

      if ((v1 == null) || (v2 == null)) {
        return 0;
      }

      if (v1 instanceof java.lang.Integer && v2 instanceof Integer) {
        result = ((Integer) v1).compareTo((Integer) v2);
      } else if (v1 instanceof java.util.Date && v2 instanceof java.util.Date) {
        result = ((Date) v1).compareTo((Date) v2);
      } else if (v1 instanceof java.lang.Double && v2 instanceof Double) {
        result = ((Double) v1).compareTo((Double) v2);
      } else if (v1 instanceof java.lang.String && v2 instanceof String) {
        result = ((String) v1).compareTo((String) v2);
      }

      if (result != 0) {
        result *= ((Integer) orderByList.get(i + 1)).intValue();

        break;
      }
    }

    return result;
  }

  /**
   * ��List�е�List���кϲ�����
   * 
   * @param list
   *          ������������List
   * @param startRow
   *          ��С��1��ʼ
   * @param iMaxResults
   *          ���ض�����
   * @return
   * @throws Exception
   */
  public List sort(List list, int startRow, int iMaxResults) throws Exception {
    if ((list == null) || list.isEmpty()) {
      return null;
    }

    int startIndex = ((iMaxResults < 0) || (startRow < 1)) ? 0 : (startRow - 1);
    int endIndex = (iMaxResults < 0) ? Integer.MAX_VALUE : (startIndex + iMaxResults);

    // ɾ��list��Ϊnull��size()==0��List
    for (int i = list.size() - 1; i >= 0; i--) {
      List l = (List) list.get(i);

      if ((l == null) || (l.size() == 0)) {
        list.remove(i);
      }
    }

    // ������, ���һ��List
    if ((orderByList == null) || (list.size() <= 1)) {
      List resultList = new ArrayList();

      for (int i = 0; i < list.size(); i++) {
        resultList.addAll((List) list.get(i));
      }

      int size = Math.min(endIndex, resultList.size());

      return resultList.subList(startIndex, size);
    }

    // ����
    List resultList = new ArrayList();

    int i, smallest, t, row_count = 0, totalListSize = list.size();
    int[] ord = new int[totalListSize];
    int[] pos = new int[totalListSize];
    List[] lists = new List[totalListSize];

    // ��ʼ��
    for (i = 0; i < totalListSize; i++) {
      ord[i] = i;
      pos[i] = 0;
      lists[i] = (List) list.get(i);
    }
    for (i = 1; i < totalListSize; i++) {
      if (compare(lists[ord[i - 1]].get(0), lists[ord[i]].get(0)) > 0) {
        t = ord[i - 1];
        ord[i - 1] = ord[i];
        ord[i] = t;
        i = 0;
      }
    }

    // ��list�ж�����бȽ�
    while (totalListSize > 0) {
      smallest = ord[0];
      row_count++;
      if (row_count > startIndex) {
        resultList.add(lists[smallest].get(pos[smallest]));
        if (endIndex <= row_count)
          break;
      }
      // ����СList��������һ��
      pos[smallest]++;

      // ��List��ĩ����
      if (pos[smallest] >= lists[smallest].size()) {
        for (i = 1; i < totalListSize; i++)
          if (ord[i] > smallest)
            --ord[i];
        totalListSize--;
        for (i = smallest; i < totalListSize; i++) {
          pos[i] = pos[i + 1];
          lists[i] = lists[i + 1];
        }
        for (i = 0; i < totalListSize; i++)
          ord[i] = ord[i + 1];
        continue;
      }
      for (i = 1; i < totalListSize; i++) {
        t = compare(lists[ord[0]].get(pos[ord[0]]), lists[ord[i]].get(pos[ord[i]]));
        if (t == 0)
          t = ord[0] - ord[i];
        if (t < 0)
          break;
      }
      t = ord[0];
      for (int j = 1; j < i; ++j)
        ord[j - 1] = ord[j];
      ord[i - 1] = t;
    }
    return resultList;
  }
}
